package demo10

import "fmt"

// --------------------------------场景1-----------------------------------

// 官方的Demo 案例 Component LeafNode CompositeNode

// 组合设计模式
// 字面理解：就是讲不同的实例组合到一个节点里，类似树形的控制
// 定义树形结构的接口规则
type Component interface{
	// 由于树形内部的实例都是一样的，那么这里使用到还是公用的接口即可
	// 定义父级别节点
	Parent() Component 		// 父级别节点的获取
	SetParent(Component) 	// 设计父级别节点
	// 定义属性
	SetName(string) 		// 定义节点的名字
	Name() string			// 获取节点的名字
	// 子节点添加
	AddChild(Component)
	// 节点的信息打印
	Print(string)
}

// 定义节点控制，分为0 和 1 的分叉点，
const (
	LeafNode = iota
	CompositeNode
) 

// 定义节点创建的构造
// 传入参数，同时构造不同的节点
func NewComponent(num int,name string) Component{
	// 构造Componsite
	var c Component
	switch num {
	case LeafNode:
		c = NewLeaf() // 子节点构造
	case CompositeNode:
		c = NewComponsite() // 父节点构造 组合节点
	}
	c.SetName(name)
	return c

}

// 由于子节点拥有父节点的方法，那么这里先定义父节点的实现
// 父节点
type component struct{
	parent Component	// 这个用来控制节点的
	name string
}

// func NewComponent() Component{
// 	return &component{}
// }
// 设置节点名字
func (c *component)SetName(name string){
	c.name = name
}
// 获取节点名字
func (c component)Name() string{
	return c.name
}
// 设置父节点
func (c *component)SetParent(parent Component){
	c.parent = parent
}
// 获取父级别节点
func (c *component)Parent()Component{
	return c.parent
}
func (c *component)AddChild(Component) {}
func (component)Print(string){}

// 定义子节点
type Leaf struct{
	component
}
func NewLeaf() Component{
	return &Leaf{}
}
func (c *Leaf)Print(pre string){
	fmt.Println(pre, c.name)
}

// 定义组合规则
type Componsite struct{
	component
	childs []Component
}
// 初始化
func NewComponsite() Component{
	return &Componsite{
		childs:make([]Component,0),
	}
}
func (c *Componsite)AddChild(component Component){
	// 配置componet的父级别节点
	component.SetParent(c)
	// 增加父级别对应的子节点
	c.childs = append(c.childs,component)
}
func (c *Componsite)Print(pre string){
	fmt.Println(pre, c.name)
	pre += "	"
	for _,v := range c.childs{
		v.Print(pre)
	}
}

// --------------------------------场景2-----------------------------------

// 组合设计模式
// 由于该模式书写起来较为繁琐 场景就写少一点
// 需求：菜单管理，分为一级和二级菜单
// 分析：menuNode子菜单节点 menuMainNode 主菜单节点  Menu菜单类， menuMain 主菜单实例， menu子菜单实例， menuIntact完整菜单
// 菜单支持，添加新菜单，和获取菜单信息

type Menu interface{
	// 父级别菜单
	Parent() Menu
	SetParent(Menu)
	// 属性
	Name() string
	SetName(string)
	// 子菜单添加
	AddChild(Menu)
	// 获取所有的信息
	Print()
}

const (
	menuNode =  iota
	menuMainNode
)

func NewMenuComponent(num int, name string) Menu{
	var m Menu
	switch num {
	case menuNode:
		m = NewMenu()
	case menuMainNode:
		m = NewMenuIntact()
	}
	// 初始化
	m.SetName(name)
	return m
}


type menuMain  struct{
	parent Menu
	name string
}
func (m *menuMain)SetName(name string){
	m.name = name
}
func (m *menuMain)Name() string{
	return m.name
}
func (m *menuMain)SetParent(parent Menu) {
	m.parent = parent
}
func (m *menuMain)Parent() Menu{
	return m.parent
}
func (m *menuMain)AddChild(Menu){}
func (m *menuMain)Print(){
	fmt.Println(m.name)
}

// node
type menu struct{
	menuMain
}

func NewMenu() Menu{
	return &menu{}
}

type menuIntact  struct{
	menuMain
	childs []Menu
}
func NewMenuIntact() Menu{
	return &menuIntact{
		childs:make([]Menu,0),
	}
}
func (m *menuIntact)AddChild(menu Menu){
	menu.SetParent(m)
	m.childs = append(m.childs, menu)
}
func (m menuIntact)Print(){
	// fmt.Println(m)
	// fmt.Println(m.Parent()) // 父级别的父级是空
	fmt.Println(m.name)		// 父级别的name 
	// fmt.Println(m.childs)
	fmt.Println("-----------------------------------------------")
	for _,v := range m.childs{
		// fmt.Println(v)
		// fmt.Println(v.Name())
		// fmt.Println(v.Parent())
		// fmt.Println(v)
		// fmt.Printf("%#v\n",v)
		v.Print() // 这里的print 有点难以理解 调用父类的方法----->使用自雷然后完成了调用
	}

	// var result []interface{}
	// result = make([]interface{},0)

	// for _,v := range m.childs{
	// 	result
	// }
}
// 该设计模式使用到的场景较少，
